/*
 *  logic.cpp
 *  
 *  Created by James Dykstra
 *	Team 5
 *
 *  Copyright 2010 Michigan Technological University. All rights reserved.
 */
#include "logic.h"
#include "sprite.h"
#include "beam.h"
#include "fighter.h"

Logic::Logic(Renderer *rnd, Map* m)
{
	renderer = rnd;
	map = m;
}
Logic::~Logic()
{
}
bool Logic::checkCollide(Sprite *spr1, Sprite *spr2)
{
	if(spr1!=0 && spr2!=0 && spr1->getHitbox()!=0 && spr2->getHitbox()!=0)
	{
		int x1 = spr1->getRect()->x+spr1->getHitbox()->getCenter()->getX();
		int y1 = spr1->getRect()->y+spr1->getHitbox()->getCenter()->getY();
		int x2 = spr2->getRect()->x+spr2->getHitbox()->getCenter()->getX();
		int y2 = spr2->getRect()->y+spr2->getHitbox()->getCenter()->getY();
		float dist = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
		//printf("x1: %i y1: %i x2: %i y2: %i Distance Between: %f\n", x1, y1, x2, y2, dist);
		if(dist < (spr1->getRadius()+spr2->getRadius()))
		{
		
			Hitbox *A = spr1->getHitbox();
			Hitbox *B = spr2->getHitbox();
			A->calcWorldCoords(spr1->getRect()->x, spr1->getRect()->y, spr1->getRect()->w, spr1->getRect()->h, spr1->getAngle());
			B->calcWorldCoords(spr2->getRect()->x, spr2->getRect()->y, spr2->getRect()->w, spr2->getRect()->h, spr2->getAngle());
		
			Hitbox *list[3];
			list[0] = A;
			list[1] = B;
			list[2] = A;
			
			Vector *p;
			Vector *tmp;
			   
			float t1;
			float t2;
			float min;
			float max;
			   
			for(int i = 0;i < 2;i++)
			{
			       for(int a = 0;a < 2;a++)
			       {
				 p = new Vector(list[i]->getWorldCoord(a+1)->getX() - list[i]->getWorldCoord(a)->getX(), list[i]->getWorldCoord(a+1)->getY() - list[i]->getWorldCoord(a)->getY());
				 p->normalize();
			      
				 tmp = list[i]->getWorldCoord(a)->projectVector(p);
				 t1 = tmp->magnitude();
				 delete tmp;
				
				 tmp = list[i]->getWorldCoord(a+1)->projectVector(p);
				 t2 = tmp->magnitude();
				 delete tmp;
				       
				 min = minimum(t1, t2);
				 max = maximum(t1, t2);
			      
				 float proj[4];
			      
				 for(int b = 0;b < 4;b++)
				 {
				    tmp = list[i+1]->getWorldCoord(b)->projectVector(p);
				    proj[b] = tmp->magnitude();
				    delete tmp;
				 }
			      
				 if(!umbrellas(min, max, proj))
				    return false;
			   }
			}
			//printf("Collision between %s and %s \n", A->getIdentifier(), B->getIdentifier());
			//printf("%s @ X:%i Y:%i Hitbox:(%f, %f) (%f, %f) (%f, %f) (%f, %f)\n", A->getIdentifier(), spr1->getRect()->x, spr1->getRect()->y, A->getWorldCoord(0)->getX(), A->getWorldCoord(0)->getY(), A->getWorldCoord(1)->getX(), A->getWorldCoord(1)->getY(), A->getWorldCoord(2)->getX(), A->getWorldCoord(2)->getY(), A->getWorldCoord(3)->getX(), A->getWorldCoord(3)->getY());
			//printf("%s @ X:%i Y:%i Hitbox:(%f, %f) (%f, %f) (%f, %f) (%f, %f)\n", B->getIdentifier(), spr2->getRect()->x, spr2->getRect()->y, B->getWorldCoord(0)->getX(), B->getWorldCoord(0)->getY(), B->getWorldCoord(1)->getX(), B->getWorldCoord(1)->getY(), B->getWorldCoord(2)->getX(), B->getWorldCoord(2)->getY(), B->getWorldCoord(3)->getX(), B->getWorldCoord(3)->getY());
	      
			return true;
		}
		return false;
	}
	else
		return false;
}

bool Logic::validMove(Sprite * sprite, int xOffset, int yOffset, float angle)
{
	bool returnValue = true;
	sprite->getRect()->x += xOffset;
	sprite->getRect()->y += yOffset;
	sprite->setAngle((sprite->getAngle()+angle));
	do {
		if(((sprite->getRect()->x + sprite->getRect()->w) > map->getMapWidth()) || (sprite->getRect()->x < 0)) {
			returnValue=false;
			break;
		}
		
		if(((sprite->getRect()->y + sprite->getRect()->h) > map->getMapHeight()) || (sprite->getRect()->y < 0)) {
			returnValue=false;
			break;
		}
		
		/*for (int i=0; i<map->getNumObstacles(); i++) {
			if (checkCollide(sprite, map->getObstacle(i))) {

				if(strcmp(sprite->getHitbox()->getIdentifier(),"Fighter")==0){
					if(!static_cast<Fighter*>(sprite)->isInMercyMode()){
						map->getObstacle(i)->damage(10);
						if(static_cast<Fighter*>(sprite)->isShielded())
							static_cast<Fighter*>(sprite)->setShielded(false);
						else
							static_cast<Fighter*>(sprite)->dmg(10);
						
						static_cast<Fighter*>(sprite)->setMercy(2);
					}

				}
				if(strcmp(sprite->getHitbox()->getIdentifier(),"Beam")==0){
					map->getObstacle(i)->damage( static_cast<Beam*>(sprite)->getDamage());
					static_cast<Beam*>(sprite)->setActive(false);
				}

				returnValue = false;
				break;
			}
		}*/
	} while (false);
	
	sprite->getRect()->x -= xOffset;
	sprite->getRect()->y -= yOffset;
	sprite->setAngle((sprite->getAngle()-angle));
	
	return returnValue;
}
bool Logic::obstacleCheck(Sprite *sprite)
{
	bool retval = false;
	for (int i=0; i<map->getNumObstacles(); i++) 
	{
		if (checkCollide(sprite, map->getObstacle(i))) 
		{
			retval = true;
			if(strcmp(sprite->getHitbox()->getIdentifier(),"Fighter")==0)
			{
				if(!static_cast<Fighter*>(sprite)->isInMercyMode())
				{
					map->getObstacle(i)->damage(10);
                                        if(static_cast<Fighter*>(sprite)->isShielded())
                                        	static_cast<Fighter*>(sprite)->setShielded(false);
                                        else
                                                static_cast<Fighter*>(sprite)->dmg(10);

                                       	static_cast<Fighter*>(sprite)->setMercy(2.0);
                                }

			}
                        if(strcmp(sprite->getHitbox()->getIdentifier(),"Beam")==0)
			{
                        	map->getObstacle(i)->damage(static_cast<Beam*>(sprite)->getDamage());
                              	static_cast<Beam*>(sprite)->setActive(false);
				break;
                        }
        	}
	}
	return retval;
}
float Logic::minimum(float a, float b)
{
	if(a < b)
		return a;
	else
		return b;
}
float Logic::maximum(float a, float b)
{
	if(a > b)
		return a;
	else
		return b;
}

bool Logic::umbrellas(float min, float max, float proj[])
{
   bool less = false;
   bool more = false;
   
   //printf("%2.2f , %2.2f\n", min, max);
   
   for(int loop = 0;loop < 4;loop++)
   {
      if(proj[loop] >= min && proj[loop] <= max)
         return true;
      else if(proj[loop] < min)
         less = true;
      else if(proj[loop] > max)
         more = true;
   }
   
   if(less && more)
      return true;
   
   return false;
}
